package edu.dhbw.mannheim;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.FetchOptions;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import com.google.appengine.api.datastore.PreparedQuery;
import com.google.appengine.api.datastore.Query;
import com.google.appengine.api.datastore.Text;
import com.google.appengine.api.users.User;
import com.google.appengine.api.users.UserService;
import com.google.appengine.api.users.UserServiceFactory;


@SuppressWarnings("serial")
public class Post extends HttpServlet {
	/**
	 * all requests concering posts
	 * type=delete: deltes a post
	 * type!=delete: creates a new post
	 */
	public void doPost(HttpServletRequest req, HttpServletResponse resp)
			throws IOException {
		
		String type = "";
		if(req.getParameter("type")!=null)
			type = req.getParameter("type");
		if(type.equals("delete")) {
			if(req.getRemoteUser() != null && Admin.isAdmin(req.getRemoteUser())) {
				DatastoreService datastore = DatastoreServiceFactory
						.getDatastoreService();
				String id = req.getParameter("id");
				
				//get the entity which shall be deleted
				Key blogKey = KeyFactory.createKey("blog", "blogblogblog");
				Query query = new Query("post", blogKey).setKeysOnly().addFilter("internalID", Query.FilterOperator.EQUAL, id);
				Entity post = datastore.prepare(query).asSingleEntity();
				
				//delete the entry
				datastore.delete(post.getKey());
				
				//return the ID
				try {
					PrintWriter out = resp.getWriter();
					out.print(id);
				} catch (IOException e) {
					e.printStackTrace();
				}
			} else {
				System.out.println("User "+req.getRemoteUser()+" has got no permissions to delete a post.");
			}
		}  else if (type.equals("reload")) {
			String user = req.getParameter("user");
			User filterUser = Admin.findUser(user);
			String offset = req.getParameter("offset");
			int offsetInt = Integer.parseInt(offset);
			String sort = req.getParameter("sort");
			PrintWriter out = null;
			try {
				out = resp.getWriter();
			} catch (IOException e1) {
				e1.printStackTrace();
			}
			if(sort != null && sort.equals("topic") && sort.equals("date")) {
				out.println(getPostsAsHTML(offsetInt, 10, filterUser, sort));
			} else {
				out.println(getPostsAsHTML(offsetInt, 10, filterUser));				
			}
		} else if (type.equals("new")) {
			if(Admin.canPost(req.getRemoteUser())) {
				UserService userService = UserServiceFactory.getUserService();
				User user = userService.getCurrentUser();
				
				Key blogKey = KeyFactory.createKey("blog", "blogblogblog");
				String topic = req.getParameter("topic");
				Text content = new Text(req.getParameter("content"));
				
				Date date = new Date();
				Entity post = new Entity("post", blogKey);
				post.setProperty("user", user);
				post.setProperty("date", date);
				post.setProperty("topic", topic);
				post.setProperty("content", content);
				post.setProperty("internalID", post.getKey().getId()+"" );
		
				DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
				datastore.put(post);
				
				//update the internalID variable with the key
				Query query = new Query("post", blogKey).addFilter("topic", Query.FilterOperator.EQUAL, topic).addFilter("date", Query.FilterOperator.EQUAL, date);
				Entity post2 = datastore.prepare(query).asSingleEntity();
				post.setProperty("internalID", post2.getKey().getId()+"" );
				datastore.delete(blogKey);
				datastore.put(post);
				resp.sendRedirect("/blog.jsp");
			}
		} else if (type.equals("edit")) {
			if(Admin.canPost(req.getRemoteUser())) {
				DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
				
				Key blogKey = KeyFactory.createKey("blog", "blogblogblog");
				String topic = req.getParameter("topic");
				Text content = new Text(req.getParameter("content"));
				String id = req.getParameter("id");
				Query query = new Query("post", blogKey).addFilter("internalID", Query.FilterOperator.EQUAL, id);
				try {
					Entity post = datastore.prepare(query).asSingleEntity();
					if(post == null) {
						resp.setStatus(400);
						resp.sendRedirect("/blog.jsp?id="+id);
						return;
					}
					post.setProperty("topic", topic);
					post.setProperty("content", content);
					datastore.put(post);
				} catch(PreparedQuery.TooManyResultsException e) {
					resp.setStatus(500);
					resp.sendRedirect("/blog.jsp?id="+id);
					return;
				}
				resp.sendRedirect("/blog.jsp?id="+id);
			}
		}
	}
	
	public static String getPostsAsHTML(int offset, int amount) {
		return getPostsAsHTML(offset,amount,null,"");
	}
	
	public static String getPostsAsHTML(int offset, int amount, User user) {
		return getPostsAsHTML(offset,amount,user,"");
	}
	
	/**
	 * @brief Create all post (filtered by parameters) as HTML code
	 * @param offset
	 * @param amount
	 * @param user only post from user
	 * @param sort sort parameter
	 * @return
	 */
	public static String getPostsAsHTML(int offset, int amount, User user, String sort) {
		//get the blog
		DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
		Key blogKey = KeyFactory.createKey("blog", "blogblogblog");
		Query query = new Query("post", blogKey);
		if(user != null) 
			query.addFilter("user",Query.FilterOperator.EQUAL, user);
		if(sort !=null && !sort.isEmpty()) {
			query.addSort(sort);
		}
		List<Entity> comments = datastore.prepare(query).asList(FetchOptions.Builder.withLimit(amount).offset(offset));
		return Post.postEntityToHTML(comments);
	}
	
	/**
	 * @brief Create the posts list and return it as string
	 * @param posts
	 * @return
	 */
	public static String postEntityToHTML(List<Entity> posts) {
		UserService userService = UserServiceFactory.getUserService();
		User user = userService.getCurrentUser();
		String outAll ="";
		for(Entity post:posts)
		{
				String deleteLink = "";
				if(user !=null && Admin.isAdmin(user.getEmail())) {
					deleteLink = "<a href='javascript:deletePost(\"" + post.getProperty("internalID")+"\")'>X</a>";
				}
			
			//content of the blog
			String output=
			"<div id=\"post"+ post.getProperty("internalID")+"\">" +
				NameDate.getNameDateHTML(post) +
				"<div class=\"small inner round\">"+
					"<table class=\"fullwidth\"><tr>" +
						"<td class=\"left\">"+
							"<a href=\"blog.jsp?id=" + (String) post.getProperty("internalID") + "\">" +
									(String) post.getProperty("topic")+
								"</a>" +
									"<blockquote class='linkblack'>";
										output+=Post.htmlSubString(((Text) post.getProperty("content")).getValue(),1000, true);
									output+="</blockquote>"+
							
						"</td>" +
						"<td class=\"right\">"+
							deleteLink+
						"</td>" +
					"</tr></table>"+
				"</div>"+
			"</div>";
			outAll+=output;
		}
		return outAll;
	}
	
	/**
	 * gets a substring of a HTML string
	 * @param html the input html string
	 * @param maxlength the length of the substring
	 * @param shortest should it vary to higher or lower values
	 * @return
	 */
	public static String htmlSubString (String html, int maxlength, boolean shortest) {
		
		//if the input string is shorter than maxlength, return the input string
		if(html.length()<maxlength) 
			return html;
		
		//delete all section tags to get at least any substring
		System.out.println(html);
		html = html.replaceAll("\\</?p>","");
		html = html.replaceAll("\\</?div>","");
		html = html.replaceAll("\\</?span>","");
		html = html.replace("\r","");
		html = html.replace("\n","");
		System.out.println(html);
		
		//initialize regular expressions
		String htmltag = "<(\\w+)((\\s+\\w+(\\s*=\\s*(?:\".*?\"|'.*?'|[^'\">\\s]+))?)+\\s*|\\s*)/?>.*?</\\1>";

		//get mathlength after the next tag
		while(html.substring(0,maxlength).lastIndexOf('<')>html.substring(0,maxlength).lastIndexOf('>')) {
			maxlength++;
		}
		
		//match all html start and end tags, otherwise get each character one by one..
		Pattern expression = Pattern.compile(htmltag, Pattern.CASE_INSENSITIVE); 
		Matcher matches = expression.matcher(html);

		int newMaxlength=maxlength;
		while(matches.find())
		{
			System.out.println("Start: "+matches.start());
			System.out.println("Ende: "+matches.end());
			System.out.println(matches.group());
			System.out.println("--------------------------------------------");
			//checks if the match starts before the end of the substring, and ends aft this
			if(matches.start() < maxlength && matches.end() > maxlength) {
				System.out.println("############################################");
				System.out.println("Start: "+matches.start());
				System.out.println("Ende: "+matches.end());
				System.out.println(matches.group());
				System.out.println("############################################");
				System.out.println("--------------------------------------------");
				if(shortest)
					if(matches.start()<newMaxlength)
						newMaxlength = matches.start();
				else
					if(matches.end()>newMaxlength)
						newMaxlength = matches.end();
			}
		}
		return html.substring(0,newMaxlength) + "...";
	}

}
